n<template>
    <div class="jdf-form-container" style="padding: 20px; max-width: 1200px; margin: 0 auto;">
        <n-alert
            v-if="error"
            title="解析错误"
            type="error"
            :description="error"
            closable
            @close="error = ''"
        />
        <n-alert
            v-else-if="!parsedData && !editorStore.rawContent"
            title="无数据"
            type="info"
            description="没有可供解析的数据。请通过文件管理器加载文件。"
        />
        <div v-else-if="parsedData">
            <n-space justify="start" style="margin-bottom: 15px;">
                <n-button @click="toggleAllCollapseItems" type="primary" secondary>
                    {{ allExpanded ? '全部折叠' : '全部展开' }}
                </n-button>
            </n-space>
            <n-collapse :default-expanded-names="activeNames" v-model:expanded-names="activeNames" accordion>
                <n-collapse-item 
                    v-for="(formGroup, groupName) in parsedData" 
                    :key="groupName" 
                    :title="translate(groupName) || groupName" 
                    :name="groupName"
                >   
                    <template #header>
                    <span class="section-title">
                        {{ translate(groupName) || groupName }}
                    </span>
                </template>
                    <!-- 在n-form外层添加层级容器 -->
                    <div class="form-section">
                    <!-- Case 1: formGroup is a single object -->
                    <n-form
                        v-if="isObject(formGroup)"
                        :model="formGroup"
                        label-placement="left"
                        label-width="auto"
                        require-mark-placement="right-hanging"
                        style="margin-top: 10px;"
                    >
                        <n-form-item
                            v-for="(value, key) in formGroup"
                            :key="key"
                            :label="translate(key) || key"
                            :path="key" 
                        >
                            <n-input 
                                v-if="isPrimitive(value)" 
                                v-model:value="formGroup[key]" 
                                clearable 
                                placeholder="请输入内容"
                                :readonly="true"
                            />
                            <!-- For arrays of primitives, like Checklist -->
                            <n-space v-else-if="isArray(value) && value.every(isPrimitive)" vertical :wrap-item="false" style="width:100%">
                                <div>
                                    <n-tag 
                                        v-for="(tagItem, index) in value" 
                                        :key="index" 
                                        closable 
                                        @close="handleRemoveTag(formGroup[key], index)"
                                        type="info"
                                        round
                                        style="margin-right: 5px; margin-bottom: 5px;"
                                    >
                                        {{ translate(tagItem) }}
                                    </n-tag>
                </div>
                                <n-input-group v-if="formGroup[key].showAddInput !== false">
                                    <n-input
                                        v-model:value="formGroup[key].newTag"
                                        placeholder="添加新项"
                                        clearable
                                        @keyup.enter="handleAddTag(formGroup[key], key, groupName)"
                                        @blur="handleAddTag(formGroup[key], key, groupName, true)" 
                                    />
                                    <n-button type="primary" ghost @click="handleAddTag(formGroup[key], key, groupName)">
                                        <template #icon><n-icon :component="AddIcon" /></template>
                                    </n-button>
                                </n-input-group>
                                 <n-button 
                                     v-else 
                                     @click="() => { formGroup[key].showAddInput = true; }" 
                                     circle 
                                     type="primary"
                                     ghost
                                 >
                                    <template #icon><n-icon :component="AddIcon" /></template>
                                 </n-button>
                            </n-space>
                            <!-- 表单化：设备资源 和 材料资源 (对象数组) -->
                            <n-space vertical v-else-if="(key === '设备资源' || key === '材料资源') && isArray(value) && value.every(isObject)" style="width:100%;">
                                <n-card
                                    v-for="(resourceItem, rIndex) in value"
                                    :key="`${groupName}-${key}-${rIndex}`"
                                    size="small"
                                    hoverable
                                    style="margin-top: 5px;"
                                    :title="translate(resourceItem.Model || resourceItem.Name || resourceItem.MaterialType || (translate(key) + ' ' + (rIndex + 1)))"
                                >
                                    <n-form
                                        :model="resourceItem"
                                        label-placement="left"
                                        label-width="auto"
                                        size="small"
                                    >
                                        <n-form-item
                                            v-for="(itemVal, itemKey_internal) in resourceItem"
                                            :key="itemKey_internal"
                                            :label="translate(itemKey_internal) || itemKey_internal"
                                            :path="itemKey_internal"
                                        >
                                            <n-input
                                                v-if="isPrimitive(itemVal)"
                                                v-model:value="resourceItem[itemKey_internal]"
                                                clearable
                                            />
                                            <!-- 嵌套表单化：对象如 InkZoneSettings, MachineSettings, ColorDensity -->
                                            <n-card v-else-if="isObject(itemVal) && (itemKey_internal === 'InkZoneSettings' || itemKey_internal === 'MachineSettings' || itemKey_internal === 'ColorDensity')" size="small" title="详细设置" style="margin-top:5px; width: 100%;">
                                                <n-form label-placement="left" label-width="auto" size="small" :model="itemVal">
                                                    <n-form-item
                                                        v-for="(subVal, subKey) in itemVal"
                                                        :key="subKey"
                                                        :label="translate(subKey) || subKey"
                                                        :path="subKey"
                                                    >
                                                        <n-input v-model:value="itemVal[subKey]" clearable />
                                                    </n-form-item>
                                                </n-form>
                                            </n-card>
                                            <RenderCell v-else :data="itemVal" />
                                        </n-form-item>
                                    </n-form>
                                </n-card>
                            </n-space>
                            <!-- 表单化：特定对象如 InkZoneSettings, MachineSettings, ColorDensity -->
                            <n-card v-else-if="isObject(value) && (key === 'InkZoneSettings' || key === 'MachineSettings' || key === 'ColorDensity')" size="small" :title="translate(key) || key" style="margin-top:5px; width: 100%;">
                                <n-form label-placement="left" label-width="auto" size="small" :model="value">
                                    <n-form-item
                                        v-for="(subVal, subKey) in value"
                                        :key="subKey"
                                        :label="translate(subKey) || subKey"
                                        :path="subKey"
                                    >
                                        <n-input v-model:value="value[subKey]" clearable />
                                    </n-form-item>
                                </n-form>
                            </n-card>
                            <RenderCell v-else :data="value" /> <!-- Non-editable display for other complex types -->
                        </n-form-item>
                    </n-form>

                    <!-- Case 2: formGroup is an array of objects -->
                    <n-space vertical v-else-if="isArray(formGroup) && formGroup.length > 0" style="width:100%;">
                        <n-card
                            v-for="(item, index) in formGroup"
                            :key="index"
                            size="small"
                            hoverable
                            style="margin-bottom: 15px;"
                        >
                             <template #header>
                                <span v-if="formGroup.length > 1 || (item && ((item.Name && item.Name !== '—') || (item.ID && item.ID !== '—') || (item.ProcessStepType && item.ProcessStepType !== '—')))">
                                    <template v-if="item.ProcessStepType && item.ProcessStepType !== '—'">
                                        {{ translate(item.ProcessStepType) }}
                                        <template v-if="item.ResourceNodeName && item.ResourceNodeName !== '—' && item.ResourceNodeName.toLowerCase() !== item.ProcessStepType.toLowerCase()">
                                                ({{ translate(item.ResourceNodeName) }})
                                        </template>
                                    </template>
                                    <template v-else>
                                        {{ translate(groupName) }} {{ index + 1 }}
                                    </template>
                                    
                                    <template v-if="item.Name && item.Name !== '—' && item.Name !== item.ProcessStepType && item.Name !== item.ResourceNodeName">
                                            - {{ item.Name }}
                                    </template>
                                    <!-- <template v-if="item.ID && item.ID !== '—'">
                                            (ID: {{ item.ID }})
                                    </template> -->
                                </span>
                                <span v-else>{{ translate(groupName) }} 项目 {{ index + 1 }}</span>
                            </template>
                            <n-form
                                v-if="item && typeof item === 'object' && Object.keys(item).length > 0"
                                :model="item"
                                label-placement="left"
                                label-width="auto"
                                size="small"
                                require-mark-placement="right-hanging"
                            >
                                <n-form-item
                                    v-for="([itemKey, itemValue]) in getFilteredEntries(item)"
                                    :key="itemKey"
                                    :label="translate(itemKey) || itemKey"
                                    :path="itemKey"
                                >
                                    <n-input
                                        v-if="isPrimitive(itemValue)"
                                        v-model:value="item[itemKey]"
                                        clearable
                                    />
                                    <n-space v-else-if="isArray(itemValue) && itemValue.every(isPrimitive)" vertical :wrap-item="false" style="width:100%">
                                        <div>
                                        <n-tag
                                            v-for="(tagItem, tagIndex) in (itemValue as EditableTagArray)"
                                            :key="tagIndex"
                                            closable
                                            @close="handleRemoveTag(itemValue as EditableTagArray, tagIndex)"
                                            type="info"
                                            round
                                            style="margin-right: 5px; margin-bottom: 5px;"
                                        >
                                            {{ translate(tagItem) }}
                                        </n-tag>
                                    </div>
                                        <n-input-group v-if="(itemValue as EditableTagArray).showAddInput !== false">
                                            <n-input
                                                v-model:value="(itemValue as EditableTagArray).newTag"
                                                placeholder="添加新项"
                                                clearable
                                                @keyup.enter="handleAddTag(itemValue as EditableTagArray, itemKey, groupName, false, index)"
                                                @blur="handleAddTag(itemValue as EditableTagArray, itemKey, groupName, true, index)"
                                            />
                                            <n-button type="primary" ghost @click="handleAddTag(itemValue as EditableTagArray, itemKey, groupName, false, index)">
                                               <template #icon><n-icon :component="AddIcon" /></template>
                                            </n-button>
                                        </n-input-group>
                                        <n-button
                                            v-else
                                            @click="() => { ensureReactiveArrayForAdd(itemValue, itemKey, groupName, index)!.showAddInput = true; }" 
                                            circle 
                                            type="primary"
                                            ghost
                                        >
                                            <template #icon><n-icon :component="AddIcon" /></template>
                                        </n-button>
                                    </n-space>
                                    <!-- 嵌套表单化：对象如 InkZoneSettings, MachineSettings, ColorDensity (在数组的item内部) -->
                                    <n-card v-else-if="isObject(itemValue) && (itemKey === 'InkZoneSettings' || itemKey === 'MachineSettings' || itemKey === 'ColorDensity')" size="small" :title="translate(itemKey) || itemKey" style="margin-top:5px; width:100%;">
                                        <n-form label-placement="left" label-width="auto" size="small" :model="itemValue">
                                            <n-form-item
                                                v-for="(subVal, subKey_internal_array) in itemValue"
                                                :key="subKey_internal_array"
                                                :label="translate(subKey_internal_array) || subKey_internal_array"
                                                :path="subKey_internal_array"
                                            >
                                                <n-input v-model:value="itemValue[subKey_internal_array]" clearable />
                                            </n-form-item>
                                        </n-form>
                                    </n-card>
                                    <RenderCell v-else :data="itemValue" />
                                </n-form-item>
                            </n-form>
                            <n-alert v-else-if="item && typeof item === 'object' && Object.keys(item).length === 0" title="此项为空对象" type="info" />
                            <n-alert v-else :title="`此项无法编辑 (${typeof item})`" type="warning" />
                        </n-card>
                    </n-space>
                    <n-alert v-else-if="isArray(formGroup) && formGroup.length === 0" title="此部分为空数组" type="info" />
                </div>
                </n-collapse-item>
            </n-collapse>
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref, watch, h, defineComponent, nextTick, type VNode } from 'vue';
import type { PropType, DefineComponent } from 'vue';
import translations from './Translation.ts';
import { useEditorStore } from '@/stores/editorStore';
import { 
    NAlert, NCollapse, NCollapseItem, NButton, NForm, NFormItem, NInput, NCard, NTag, NIcon, NSpace, NInputGroup 
} from 'naive-ui';
import { AddOutline as AddIcon } from '@vicons/ionicons5';

// Define a type for arrays that will be used with the tag editor
interface EditableTagArray extends Array<string | number | boolean> {
    newTag?: string;
    showAddInput?: boolean;
}

const editorStore = useEditorStore();

const parsedData = ref<Record<string, any> | null>(null);
const error = ref<string>('');
const activeNames = ref<string[] | string | null>([]); // n-collapse can take string for single, or array for multiple active
const allExpanded = ref<boolean>(true); // Default to all expanded

const toggleAllCollapseItems = () => {
    allExpanded.value = !allExpanded.value;
    if (parsedData.value) {
        if (allExpanded.value) {
            activeNames.value = Object.keys(parsedData.value);
        } else {
            activeNames.value = [];
        }
    }
};

const isObject = (obj: any): obj is Record<string, any> => typeof obj === 'object' && !Array.isArray(obj) && obj !== null;
const isArray = (arr: any): arr is any[] => Array.isArray(arr);
const isPrimitive = (val: any): boolean => typeof val !== 'object' || val === null;

// Helper function to filter entries for form items
const getFilteredEntries = (itemObject: Record<string, any>) => {
  const excludedKeys = ['ProcessStepType', 'ResourceNodeName', 'Name', 'ID', 'ResourceClass'];
  if (!itemObject || typeof itemObject !== 'object') return [];
  return Object.entries(itemObject).filter(([key]) => !excludedKeys.includes(key));
};

// Helper function to ensure reactivity when adding tags
const ensureReactiveArrayForAdd = (
    arr: any,
    keyToUpdate: string,
    groupNameKey: string,
    itemIndex?: number
): EditableTagArray | null => {
    let targetArray: any = arr;
    if (!Array.isArray(arr)) {
        console.warn("Target for adding tag is not an array, attempting to re-evaluate path");
        if (parsedData.value && parsedData.value[groupNameKey]) {
            if (itemIndex !== undefined && 
                Array.isArray(parsedData.value[groupNameKey]) && 
                parsedData.value[groupNameKey][itemIndex] &&
                parsedData.value[groupNameKey][itemIndex][keyToUpdate] !== undefined
            ) {
                targetArray = parsedData.value[groupNameKey][itemIndex][keyToUpdate];
            } else if (itemIndex === undefined && parsedData.value[groupNameKey][keyToUpdate] !== undefined) {
                targetArray = parsedData.value[groupNameKey][keyToUpdate];
            }
            
            if (!Array.isArray(targetArray)) {
                console.warn("Re-evaluated path did not yield an array for key:", keyToUpdate, "in group:", groupNameKey, "at index:", itemIndex);
                return null;
            }
        } else {
            return null;
        }
    }
    
    const editableArray = targetArray as EditableTagArray;

    if (typeof editableArray.newTag === 'undefined') {
        editableArray.newTag = '';
    }
    if (typeof editableArray.showAddInput === 'undefined') {
       editableArray.showAddInput = false;
    }
    return editableArray;
};

const handleAddTag = (
    arr: any, 
    keyToUpdate: string, 
    groupNameKey: string, 
    onBlur = false,
    itemIndex?: number
) => {
    const targetArray = ensureReactiveArrayForAdd(arr, keyToUpdate, groupNameKey, itemIndex);
    if (targetArray && typeof targetArray.newTag === 'string' && targetArray.newTag.trim() !== '') {
        targetArray.push(targetArray.newTag.trim());
        targetArray.newTag = ''; // Clear input
        if(onBlur && typeof targetArray.showAddInput !== 'undefined') {
            targetArray.showAddInput = false;
        }
    } else if (targetArray && onBlur && typeof targetArray.showAddInput !== 'undefined') {
        targetArray.showAddInput = false;
    }
};

const handleRemoveTag = (arr: any, index: number) => {
    const targetArray = arr as EditableTagArray;
    if (Array.isArray(targetArray)) {
        targetArray.splice(index, 1);
    }
};

const RenderCell: DefineComponent<{
    data: PropType<any>;
    // pathPrefix?: PropType<string>;
}> = defineComponent({
    name: 'RenderCell',
    props: {
        data: {
            type: Object as PropType<any>,
            default: null
        },
        // pathPrefix: { type: String, default: '' }
    },
    setup(props): () => VNode {
        const translateLocal = (key: any): string => {
            if (key === null || key === undefined) return '—';
            // Ensure key is a string before looking up in translations
            const stringKey = String(key);
            return (translations as Record<string, string>)[stringKey] || stringKey;
        };

        if (isPrimitive(props.data) || props.data === null || props.data === undefined) {
            return () => h('span', { style: 'padding: 4px 0; display: inline-block;' },translateLocal(props.data));
        }

        if (isArray(props.data)) {
            if (props.data.length === 0) {
                return () => h(NTag, { type: 'info', size: 'small', round: true }, () => '[空数组]');
            }
            // If it's an array of primitives, render as tags (non-editable here as main template handles editable tags)
            if (props.data.every(item => isPrimitive(item))) {
                const tags = props.data.map((item: any, index: number) => 
                    h(NTag, { 
                        key: `tag-${index}`, // Add key for list rendering
                        style: 'margin-right: 5px; margin-bottom: 5px;', 
                        size: 'small',
                        round: true, 
                        type: 'info'
                    }, () => translateLocal(item))
                );
                return () => h(NSpace, {}, () => tags);
            } else {
                // Array of objects or mixed content: render each item in a card, recursively calling RenderCell
                return () => h(NSpace, { vertical: true, style: "width:100%; margin-top: 5px;" }, () =>
                    (props.data as any[]).map((item: any, index: number) =>
                        h(NCard, { 
                            key: `array-card-${index}`, // Add key for list rendering
                            title: translateLocal(`项 ${index + 1}`),
                            size: 'small', 
                            bordered: true, 
                            style: 'margin-bottom: 8px;' 
                        }, () =>
                            h(RenderCell, { data: item })
                        )
                    )
                );
            }
        }

        if (isObject(props.data)) {
            // Object: render as a form with form items for each key-value pair
            const formItems: VNode[] = Object.entries(props.data).map(([key, value]): VNode => {
                return h(NFormItem, { 
                        label: translateLocal(key), 
                        // path: `${props.pathPrefix}.${key}` // Construct unique path for potential validation or v-model strategies
                        key: `form-item-${key}` // Add key for list rendering
                    }, 
                    () => {
                        if (isPrimitive(value)) {
                            return h(NInput, {
                                value: String(value), // Ensure value is string for NInput
                                'onUpdate:value': (newValue: string) => {
                                    // Attempt to update the reactive data directly
                                    // This assumes props.data is a reactive object part of the larger parsedData structure.
                                    // Type conversion might be needed if original value was not string.
                                    let updatedValue: any = newValue;
                                    if(typeof value === 'number'){ updatedValue = parseFloat(newValue);}
                                    else if(typeof value === 'boolean'){ updatedValue = newValue.toLowerCase() === 'true';}
                                     (props.data as Record<string, any>)[key] = updatedValue;
                                },
                                clearable: true,
                                placeholder: `输入 ${translateLocal(key)}`
                            } as any);
                        } else {
                            // Value is an object or array, recursive call to RenderCell
                            return h(RenderCell, { data: value });
                        }
                    }
                );
            });
            if (formItems.length === 0) {
                 return () => h(NTag, { type: 'info', size: 'small', round: true }, () => '[空对象]');
            }
            return () => h(NForm, { 
                model: props.data, // Bind model for potential validation, though direct updates are handled in NInput
                labelPlacement: 'left', 
                labelWidth: 'auto', 
                size: 'small',
                style: 'padding: 8px; border: 1px solid var(--n-border-color, #e0e0e0); border-radius: 3px; margin-top: 5px;'
            }, () => formItems);
        }
        
        return () => h(NTag, { type: 'error', size:'small', round: true }, () => '无法渲染的数据') as VNode;
    }
});

const objectToTableData = (obj: Record<string, any>): { key: string; value: any }[] => {
    return Object.entries(obj).map(([key, value]) => ({ key, value }));
};

const parseJdf = (xmlContent: string | null): Record<string, any> | null => {
    if (!xmlContent || xmlContent.trim() === '') {
        parsedData.value = null;
        activeNames.value = [];
        error.value = '';
        allExpanded.value = true; // Reset on no content
        return null;
    }
    try {
        const parser = new DOMParser();
        const xmlDoc = parser.parseFromString(xmlContent, "application/xml");

        const parserErrorElements = xmlDoc.getElementsByTagName("parsererror");
        if (parserErrorElements.length > 0) {
            const firstErrorElement = parserErrorElements[0];
            let errorMessage = "Unknown XML parsing error occurred.";
            const errorDiv = firstErrorElement.querySelector('div');
            if (errorDiv && errorDiv.textContent) {
                errorMessage = errorDiv.textContent.trim();
            } else if (firstErrorElement.textContent) {
                errorMessage = firstErrorElement.textContent.trim();
            }
            throw new Error(`XML parsing error: ${errorMessage}`);
        }

        if (xmlDoc.documentElement && xmlDoc.documentElement.nodeName === "parsererror") {
             throw new Error("Invalid XML content: Root element is a parsererror.");
        }
        if (!xmlDoc.documentElement) {
            throw new Error("Invalid XML content: No document element found after parsing.");
        }

        const rootElement = xmlDoc.documentElement;
        const nsResolver = (prefix: string | null): string | null => {
            const ns: { [key: string]: string } = { 'jdf': 'http://www.CIP4.org/JDFSchema_1_1' };
            return prefix ? ns[prefix] : null;
        };
        const evaluate = (expression: string, contextNode: Node, type: number): XPathResult => {
            return xmlDoc.evaluate(expression, contextNode, nsResolver, type, null);
        };
        const xpath = (expression: string, context: Node = xmlDoc): XPathResult => {
            return evaluate(expression, context, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
        };
        const getSingleNode = (expression: string, context: Node = xmlDoc): Node | null => {
            const result = xpath(expression, context);
            return result.snapshotLength === 1 ? result.snapshotItem(0) : null;
        };
        const getNodeText = (parent: Node | null, xpathExpr: string): string => {
            if (!parent) return '—';
        const nodes = xpath(xpathExpr, parent);
            const texts: string[] = [];
        for (let i = 0; i < nodes.snapshotLength; i++) {
            const node = nodes.snapshotItem(i);
                if (node && node.textContent) {
            texts.push(node.textContent.trim());
                }
        }
        return texts.join('\n') || '—';
    };
        const getAttributeSafe = (node: Node | null, attributeName: string): string => {
            if (node && node instanceof Element) {
                return node.getAttribute(attributeName) || '—';
            }
            return '—';
        };
        const getQuantity = (orderParams: Node | null): string => {
            if (!orderParams) return '—';
        const quantityNode = getSingleNode('./jdf:Quantity', orderParams);
            return quantityNode ? `${getAttributeSafe(quantityNode, 'Unit')}: ${quantityNode.textContent?.trim() || '—'}` : '—';
        };

        const extractResourceInfo = (node: Node | null): Record<string, any> => {
            const data: Record<string, any> = {};
            if (!node) return data;
            const children = xpath('./jdf:*', node);
            for (let i = 0; i < children.snapshotLength; i++) {
                const child = children.snapshotItem(i) as Element;
                if (!child) continue;
                const tag = child.localName;
                switch (tag) {
                    case 'File': data['File'] = child.getAttribute('URL') || '—'; break;
                    case 'ColorSpace': data['ColorSpace'] = child.textContent?.trim() || '—'; break;
                    case 'PageBox': data['PageBox'] = `${child.getAttribute('Width')}${child.getAttribute('Unit')} × ${child.getAttribute('Height')}${child.getAttribute('Unit')}`; break;
                    case 'Bleed': data['Bleed'] = `${child.getAttribute('Size')}${child.getAttribute('Unit')}`; break;
                    case 'InkType': data['InkType'] = child.textContent?.trim() || '—'; break;
                    case 'PrintResolution': data['PrintResolution'] = child.textContent?.trim() || '—'; break;
                    case 'MediaType': data['MediaType'] = child.textContent?.trim() || '—'; break;
                    case 'Width': data['Width'] = `${child.textContent?.trim()}${child.getAttribute('Unit') || ''}`; break;
                    case 'Quality': data['Quality'] = child.textContent?.trim() || '—'; break;
                    case 'Temperature': data['Temperature'] = child.textContent?.trim() || '—'; break;
                    case 'Time': data['Time'] = child.textContent?.trim() || '—'; break;
                    case 'DesignSoftware': data['DesignSoftware'] = child.textContent?.trim() || '—'; break;
                    case 'PreflightStatus': data['PreflightStatus'] = child.textContent?.trim() || '—'; break;
                    case 'CheckedBy': data['CheckedBy'] = child.textContent?.trim() || '—'; break;
                    case 'RIPStatus': data['RIPStatus'] = child.textContent?.trim() || '—'; break;
                    case 'RIPTime': data['RIPTime'] = child.textContent?.trim() || '—'; break;
                    case 'InkZoneSettings': {
                        const inkZoneSettings: Record<string, string> = {};
                        const inkChildren = xpath('./jdf:*', child);
                        for (let j = 0; j < inkChildren.snapshotLength; j++) {
                            const inkChild = inkChildren.snapshotItem(j) as Element;
                            if (inkChild && inkChild.localName && inkChild.textContent) {
                               inkZoneSettings[inkChild.localName] = inkChild.textContent.trim();
                            }
                        }
                        data['InkZoneSettings'] = inkZoneSettings;
                        break;
                    }
                    case 'PrintSpeed': data['PrintSpeed'] = `${child.textContent?.trim()} ${getNodeText(child, 'jdf:Unit')}`; break;
                    case 'Humidity': data['Humidity'] = child.textContent?.trim() || '—'; break;
                    case 'Model': data['Model'] = child.textContent?.trim() || '—'; break;
                    case 'MaxSheetSize': data['MaxSheetSize'] = child.textContent?.trim() || '—'; break;
                    case 'FoldingModes': data['FoldingModes'] = child.textContent?.trim() || '—'; break;
                    case 'MaxPaperSize': data['MaxPaperSize'] = child.textContent?.trim() || '—'; break;
                    case 'MaxEmbossingArea': data['MaxEmbossingArea'] = child.textContent?.trim() || '—'; break;
                    case 'PressureRange': data['PressureRange'] = child.textContent?.trim() || '—'; break;
                    case 'MaterialType': data['MaterialType'] = child.textContent?.trim() || '—'; break;
                    case 'Brand': data['Brand'] = child.textContent?.trim() || '—'; break;
                    case 'SurfaceTreatment': data['SurfaceTreatment'] = child.textContent?.trim() || '—'; break;
                    case 'ColorTolerance': data['ColorTolerance'] = child.textContent?.trim() || '—'; break;
                    case 'EmbossingConsistency': data['EmbossingConsistency'] = child.textContent?.trim() || '—'; break;
                    case 'FoldingAccuracy': data['FoldingAccuracy'] = child.textContent?.trim() || '—'; break;
                    case 'ChecklistItem':
                        if (!data['Checklist']) {
                            data['Checklist'] = [];
                        }
                        if (Array.isArray(data['Checklist'])) {
                           data['Checklist'].push(child.textContent?.trim() || '—');
                        }
                        break;
                    case 'RIPSoftware': data['RIPSoftware'] = child.textContent?.trim() || '—'; break;
                    case 'OutputFormat': data['OutputFormat'] = child.textContent?.trim() || '—'; break;
                    case 'ColorProfile': data['ColorProfile'] = child.textContent?.trim() || '—'; break;
                    case 'ColorDensity': {
                        const colorDensity: Record<string, string> = {};
                        const colorChildren = xpath('./jdf:*', child);
                        for (let j = 0; j < colorChildren.snapshotLength; j++) {
                            const colorChild = colorChildren.snapshotItem(j) as Element;
                            if (colorChild && colorChild.localName && colorChild.textContent) {
                                colorDensity[colorChild.localName] = colorChild.textContent.trim();
                            }
                        }
                        data['ColorDensity'] = colorDensity;
                        break;
                    }
                    case 'RegistrationTolerance': data['RegistrationTolerance'] = child.textContent?.trim() || '—'; break;
                    case 'FoldType': data['FoldType'] = child.textContent?.trim() || '—'; break;
                    case 'FoldPosition': data['FoldPosition'] = child.textContent?.trim() || '—'; break;
                    case 'FoldingSpeed': data['FoldingSpeed'] = `${child.textContent?.trim()} SheetsPerMinute`; break;
                    case 'Pressure': data['Pressure'] = child.textContent?.trim() || '—'; break;
                    case 'EmbossDesign': data['EmbossDesign'] = child.textContent?.trim() || '—'; break;
                    case 'EmbossingTemperature': data['EmbossingTemperature'] = child.textContent?.trim() || '—'; break;
                    case 'EmbossingArea': data['EmbossingArea'] = child.textContent?.trim() || '—'; break;
                    case 'MachineSettings': {
                        const machineSettings: Record<string, string> = {};
                        const machineChildren = xpath('./jdf:*', child);
                        for (let j = 0; j < machineChildren.snapshotLength; j++) {
                            const machineChild = machineChildren.snapshotItem(j) as Element;
                            if (machineChild && machineChild.localName && machineChild.textContent) {
                                machineSettings[machineChild.localName] = machineChild.textContent.trim();
                            }
                        }
                        data['MachineSettings'] = machineSettings;
                        break;
                    }
                    case 'EmbossDepth': data['EmbossDepth'] = child.textContent?.trim() || '—'; break;
                    case 'DieID': data['DieID'] = child.textContent?.trim() || '—'; break;
                    case 'PressureSetting': data['PressureSetting'] = child.textContent?.trim() || '—'; break;
                    default:
                        data[tag] = child.textContent?.trim() || '—';
                }
            }
            return data;
        };
        const getDeviceResources = (resourceAllocation: Node | null): Record<string, any>[] => {
            if (!resourceAllocation) return [];
        const devices = xpath('./jdf:Device', resourceAllocation);
            const deviceDescriptions: Record<string, any>[] = [];
        for (let i = 0; i < devices.snapshotLength; i++) {
            const device = devices.snapshotItem(i);
            const deviceInfo = extractResourceInfo(device);
            deviceDescriptions.push(deviceInfo);
        }
        return deviceDescriptions;
    };
        const getMaterialResources = (resourceAllocation: Node | null): Record<string, any>[] => {
            if (!resourceAllocation) return [];
        const materials = xpath('./jdf:Material', resourceAllocation);
            const materialDescriptions: Record<string, any>[] = [];
        for (let i = 0; i < materials.snapshotLength; i++) {
            const material = materials.snapshotItem(i);
            const materialInfo = extractResourceInfo(material);
            materialDescriptions.push(materialInfo);
        }
        return materialDescriptions;
    };
        const getCost = (costEstimation: Node | null, xpathExpr: string): string => {
        if (!costEstimation) return '—';
        const costNode = getSingleNode(xpathExpr, costEstimation);
            return costNode ? `${getAttributeSafe(costNode, 'Currency')}: ${costNode.textContent?.trim() || '—'}` : '—';
        };

        const forms: Record<string, any> = {};
        const orderInfoNode = getSingleNode('//jdf:OrderInfo');
        if (orderInfoNode) {
            const customerDetails = getSingleNode('./jdf:CustomerDetails', orderInfoNode);
            const orderParams = getSingleNode('./jdf:OrderParameters', orderInfoNode);
        forms['订单信息'] = {
            '客户公司': getNodeText(customerDetails, 'jdf:Company'),
            '联系人': getNodeText(customerDetails, 'jdf:Contact'),
            '联系电话': getNodeText(customerDetails, 'jdf:Phone'),
            '邮箱': getNodeText(customerDetails, 'jdf:Email'),
            '街道地址': getNodeText(customerDetails, 'jdf:Address/jdf:Street'),
            '城市': getNodeText(customerDetails, 'jdf:Address/jdf:City'),
            '邮政编码': getNodeText(customerDetails, 'jdf:Address/jdf:PostalCode'),
            '交货日期': getNodeText(orderParams, 'jdf:DeliveryDate'),
            '订单数量': getQuantity(orderParams),
            '优先级': getNodeText(orderParams, 'jdf:Priority'),
            '产品描述': getNodeText(orderParams, 'jdf:ProductDescription'),
            '特殊说明': getNodeText(orderParams, 'jdf:SpecialInstructions/jdf:Instruction'),
        };
    }
        const productionInfoNode = getSingleNode('//jdf:ProductionInfo');
        if (productionInfoNode) {
            const schedule = getSingleNode('./jdf:Schedule', productionInfoNode);
            const resourceAllocation = getSingleNode('./jdf:ResourceAllocation', productionInfoNode);
            const costEstimation = getSingleNode('./jdf:CostEstimation', productionInfoNode);
            const qualityRequirements = getSingleNode('./jdf:QualityRequirements', productionInfoNode);
        forms['生产信息'] = {
            '开始时间': getNodeText(schedule, 'jdf:StartTime'),
            '结束时间': getNodeText(schedule, 'jdf:EndTime'),
            '设备资源': getDeviceResources(resourceAllocation),
            '材料资源': getMaterialResources(resourceAllocation),
            '材料成本': getCost(costEstimation, 'jdf:MaterialCost'),
            '人工成本': getCost(costEstimation, 'jdf:LaborCost'),
            '设备成本': getCost(costEstimation, 'jdf:EquipmentCost'),
            '总成本': getCost(costEstimation, 'jdf:TotalCost'),
            '颜色公差': getNodeText(qualityRequirements, 'jdf:ColorTolerance'),
            };
        }
        const auditPoolNode = getSingleNode('//jdf:AuditPool');
        if (auditPoolNode) {
            const createdNode = getSingleNode('./jdf:Created', auditPoolNode);
            const modifiedNode = getSingleNode('./jdf:Modified', auditPoolNode);
        forms['审计信息'] = {
                '创建代理名称': getAttributeSafe(createdNode, 'AgentName'),
                '创建代理版本': getAttributeSafe(createdNode, 'AgentVersion'),
                '创建时间': getAttributeSafe(createdNode, 'TimeStamp'),
                '修改代理名称': getAttributeSafe(modifiedNode, 'AgentName'),
                '修改代理版本': getAttributeSafe(modifiedNode, 'AgentVersion'),
                '修改时间': getAttributeSafe(modifiedNode, 'TimeStamp'),
            };
        }
        const processGroupNode = getSingleNode('//jdf:ProcessGroup');
        const resourcePoolNode = getSingleNode('//jdf:ResourcePool');
        if (processGroupNode && resourcePoolNode) {
            const prepressForms: Record<string, any>[] = [];
            const printingForms: Record<string, any>[] = [];
            const finishingForms: Record<string, any>[] = [];
            const mainProcesses = xpath('./jdf:Process', processGroupNode);
        for (let i = 0; i < mainProcesses.snapshotLength; i++) {
                const mainProcess = mainProcesses.snapshotItem(i) as Element;
                if (!mainProcess) continue;
            const mainType = mainProcess.getAttribute('Type');
            const subProcesses = xpath('./jdf:Process', mainProcess);
            for (let j = 0; j < subProcesses.snapshotLength; j++) {
                    const subProcess = subProcesses.snapshotItem(j) as Element;
                    if (!subProcess) continue;
                const resourceUsage = subProcess.getAttribute('ResourceUsage');
                    const processType = subProcess.getAttribute('Type');

                if (resourceUsage) {
                    const resourceIds = resourceUsage.split(',').map(id => id.trim());
                        const collectedResourcesForSubProcess: Record<string, any>[] = [];

                    resourceIds.forEach(resourceId => {
                            const resourceNode = getSingleNode(`//*[@ID='${resourceId}']`, resourcePoolNode);
                        if (resourceNode) {
                                const resourceChildrenData = extractResourceInfo(resourceNode);
                                const resourceAttributesAndDerivedProps = {
                                    ID: getAttributeSafe(resourceNode, 'ID'),
                                    Name: getAttributeSafe(resourceNode, 'Name'),
                                    ResourceClass: getAttributeSafe(resourceNode, 'Class'),
                                    ResourceNodeName: resourceNode instanceof Element ? resourceNode.localName : '—',
                                    ProcessStepType: processType,
                                };
                                
                                const combinedData: Record<string, any> = { ...resourceChildrenData };
                                for (const key in resourceAttributesAndDerivedProps) {
                                    if (Object.prototype.hasOwnProperty.call(resourceAttributesAndDerivedProps, key)) {
                                        // @ts-ignore
                                        combinedData[key] = resourceAttributesAndDerivedProps[key];
                                    }
                                }

                                const finalFilteredData: Record<string, any> = {};
                                const keysToAlwaysExclude = ['ResourceClass'];
                                for (const key in combinedData) {
                                    if (Object.prototype.hasOwnProperty.call(combinedData, key)) {
                                        if (keysToAlwaysExclude.includes(key)) continue;
                                        if (key === 'Name' && combinedData[key] === '—') continue;
                                        finalFilteredData[key] = combinedData[key];
                                    }
                                }
                                
                                if (Object.keys(finalFilteredData).length > 0) {
                                    collectedResourcesForSubProcess.push(finalFilteredData);
                                }
                            }
                        });

                        if (mainType === 'Prepress') {
                            prepressForms.push(...collectedResourcesForSubProcess);
                        } else if (mainType === 'Printing') {
                            printingForms.push(...collectedResourcesForSubProcess);
                        } else if (mainType === 'Finishing') {
                            finishingForms.push(...collectedResourcesForSubProcess);
                        }
                    }
                }
            }
            if (prepressForms.length > 0) forms['印前表单'] = prepressForms;
            if (printingForms.length > 0) forms['印刷表单'] = printingForms;
            if (finishingForms.length > 0) forms['印后表单'] = finishingForms;
        }

        return Object.keys(forms).length > 0 ? forms : null;
    } catch (err: any) {
        console.error("Error parsing JDF content in JDFform.vue:", err);
        const message = (typeof err.message === 'string') ? err.message : '未知解析错误';
        error.value = `JDF内容解析失败: ${message}`;
        parsedData.value = null;
        activeNames.value = [];
        allExpanded.value = true; // Reset on error
        return null;
    }
};

const translate = (key: any): any => {
    if (typeof key === 'string') {
        return (translations as Record<string, string>)[key] || key;
    }
    return key;
};

watch(() => editorStore.rawContent, (newRawContent) => {
    if (newRawContent && newRawContent.trim() !== '') {
        error.value = '';
        try {
            const currentParsedData = parseJdf(newRawContent);
            parsedData.value = currentParsedData;
            if (currentParsedData) {
                if (allExpanded.value) { // Respect current allExpanded state
                    activeNames.value = Object.keys(currentParsedData);
                } else {
                    activeNames.value = [];
                }
        } else {
                activeNames.value = [];
            }
        } catch (err: any) {
            console.error("Error parsing JDF content in JDFform.vue:", err);
            const message = (typeof err.message === 'string') ? err.message : '未知解析错误';
            error.value = `JDF内容解析失败: ${message}`;
            parsedData.value = null;
            activeNames.value = []; 
        }
    } else {
        parsedData.value = null;
        activeNames.value = []; 
        error.value = ''; 
        allExpanded.value = true; // Reset on empty content
    }
}, { immediate: true });

</script>

<style scoped>
/* All CSS removed as per user request */

/* 层级式折叠面板样式 */
.structured-collapse {
    --n-title-font-size: 16px;
    --n-border-radius: 8px;
    gap: 12px; /* 折叠项间距 */
}

/* 大标题样式增强 */
.section-title {
    font-size: 24px;
    font-weight: 700;
    color: #2c3e50;
    position: relative;
    padding-left: 12px;
}

.section-title::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 4px;
    height: 70%;
    background: #3498db;
    border-radius: 2px;
}

/* 表单区块容器 */
.form-section {
    background: #f8f9fa;
    border-radius: 6px;
    padding: 16px;
    margin-top: 8px;
    box-shadow: 0 1px 2px rgba(0,0,0,0.05);
}

/* 嵌套卡片样式 */
.n-card {
    margin-bottom: 12px;
    border-left: 3px solid #e9ecef !important;
    transition: all 0.2s;
}

.n-card:hover {
    border-left-color: #3498db !important;
    transform: translateX(4px);
}

/* 表单项增强 */
.n-form-item {
    margin-bottom: 8px;
    padding: 8px 12px;
    background: white;
    border-radius: 4px;
    border: 1px solid #eee;
}

/* 数组项特殊样式 */
.n-space.vertical {
    background: #fcfcfc;
    padding: 12px;
    border-radius: 6px;
    border: 1px solid #f0f0f0;
}

/* 输入框禁用状态统一 */
.n-input:read-only {
    background-color: #f8f9fa;
    border-color: #e9ecef;
}

/* 层级缩进
.n-collapse-item >>> .n-collapse-item__content-inner {
    padding-left: 20px !important;
    border-left: 2px dashed #eee;
    margin-left: 8px;
} */
</style>